home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ddj1191.zip / STRUPROG.ASC < prev   
Text File  |  1991-10-18  |  12KB  |  389 lines

  1. _STRUCTURED PROGRAMMING COLUMN_
  2. by Jeff Duntemann
  3.  
  4.  
  5.  
  6. [LISTING ONE]
  7.  
  8. PROGRAM HCalc;
  9.  
  10. USES App,Dialogs,Objects,Views,Menus,Drivers,
  11.      FInput,    { By Allen Bauer; on CompuServe BPROGA }
  12.      Mortgage;  { By Jeff Duntemann; from DDJ 10/91 }
  13.  
  14. CONST
  15.   cmNewMortgage  = 199;
  16.   cmCloseAll     = 198;
  17.   cmCloseBC      = 197;
  18.   cmPrintSummary = 196;
  19.   WindowCount : Integer = 0;
  20.  
  21. TYPE
  22.   MortgageDialogData =
  23.     RECORD
  24.       PrincipalData : Real;
  25.       InterestData  : Real;
  26.       PeriodsData   : Integer;
  27.     END;
  28.  
  29.   THouseCalcApp =
  30.     OBJECT(TApplication)
  31.       InitDialog : PDialog;  { Dialog for initializing a mortgage }
  32.       CONSTRUCTOR Init;
  33.       PROCEDURE   InitMenuBar; VIRTUAL;
  34.       PROCEDURE   CloseAll;
  35.       PROCEDURE   HandleEvent(VAR Event : TEvent); VIRTUAL;
  36.       PROCEDURE   NewMortgage;
  37.     END;
  38.  
  39.   PMortgageTopInterior = ^TMortgageTopInterior;
  40.   TMortgageTopInterior =
  41.     OBJECT(TView)
  42.       Mortgage    : PMortgage;
  43.       CONSTRUCTOR Init(VAR Bounds : TRect);
  44.       PROCEDURE   Draw; VIRTUAL;
  45.     END;
  46.  
  47.   PMortgageBottomInterior = ^TMortgageBottomInterior;
  48.   TMortgageBottomInterior =
  49.     OBJECT(TScroller)
  50.       { Points to Mortgage object owned by TMortgageView }
  51.       Mortgage    : PMortgage;
  52.       CONSTRUCTOR Init(VAR Bounds : TRect;
  53.                        AHScrollBar, AVScrollbar : PScrollBar);
  54.       PROCEDURE   Draw; VIRTUAL;
  55.     END;
  56.  
  57.   PMortgageView = ^TMortgageView;
  58.   TMortgageView =
  59.     OBJECT(TWindow)
  60.       Mortgage    : TMortgage;
  61.       CONSTRUCTOR Init(VAR Bounds  : TRect;
  62.                        ATitle  : TTitleStr;
  63.                        ANumber : Integer;
  64.                        InitMortgageData :
  65.                        MortgageDialogData);
  66.       PROCEDURE   HandleEvent(Var Event : TEvent); VIRTUAL;
  67.       PROCEDURE   PrintSummary;
  68.       DESTRUCTOR  Done; VIRTUAL;
  69.     END;
  70.  
  71. CONST
  72.   DefaultMortgageData : MortgageDialogData =
  73.     (PrincipalData : 100000;
  74.      InterestData  : 10.0;
  75.      PeriodsData   : 360);
  76.  
  77. {------------------------------}
  78. {   METHODS: THouseCalcApp     }
  79. {------------------------------}
  80.  
  81. CONSTRUCTOR THouseCalcApp.Init;
  82.  
  83. VAR
  84.   R : TRect;
  85.   aView      : PView;
  86.  
  87. BEGIN
  88.   TApplication.Init;  { Always call the parent's constructor first! }
  89.  
  90.   { Create the dialog for initializing a mortgage: }
  91.   R.Assign(20,5,60,16);
  92.   InitDialog := New(PDialog,Init(R,'Define Mortgage Parameters'));
  93.   WITH InitDialog^ DO
  94.     BEGIN
  95.       { First item in the dialog box is input line for principal: }
  96.       R.Assign(3,3,13,4);
  97.       aView := New(PFInputLine,Init(R,8,DRealSet,DReal,0));
  98.       Insert(aView);
  99.       R.Assign(2,2,12,3);
  100.       Insert(New(PLabel,Init(R,'Principal',aView)));
  101.  
  102.       { Next is the input line for interest rate: }
  103.       R.Assign(17,3,26,4);
  104.       aView := New(PFInputLine,Init(R,6,DRealSet,DReal,3));
  105.       Insert(aView);
  106.       R.Assign(16,2,25,3);
  107.       Insert(New(PLabel,Init(R,'Interest',aView)));
  108.       R.Assign(26,3,27,4);   { Add a static text "%" sign }
  109.       Insert(New(PStaticText,Init(R,'%')));
  110.  
  111.       { Up next is the input line for number of periods: }
  112.       R.Assign(31,3,36,4);
  113.       aView := New(PFInputLine,Init(R,3,DUnsignedSet,DInteger,0));
  114.       Insert(aView);
  115.       R.Assign(29,2,37,3);
  116.       Insert(New(PLabel,Init(R,'Periods',aView)));
  117.  
  118.       { These are standard buttons for the OK and Cancel commands: }
  119.       R.Assign(8,8,16,10);
  120.       Insert(New(PButton,Init(R,'~O~K',cmOK,bfDefault)));
  121.       R.Assign(22,8,32,10);
  122.       Insert(New(PButton,Init(R,'Cancel',cmCancel,bfNormal)));
  123.     END;
  124. END;
  125.  
  126. { This method sends out a broadcast message to all views.  Only the
  127. { mortgage windows know how to respond to it, so when cmCloseBC is
  128. { issued, only the mortgage windows react--by closing. }
  129.  
  130. PROCEDURE THouseCalcApp.CloseAll;
  131.  
  132. VAR
  133.   Who : Pointer;
  134.  
  135. BEGIN
  136.   Who := Message(Desktop,evBroadcast,cmCloseBC,@Self);
  137. END;
  138.  
  139. PROCEDURE THouseCalcApp.HandleEvent(VAR Event : TEvent);
  140.  
  141. BEGIN
  142.   TApplication.HandleEvent(Event);
  143.   IF Event.What = evCommand THEN
  144.     BEGIN
  145.       CASE Event.Command OF
  146.         cmNewMortgage : NewMortgage;
  147.         cmCloseAll    : CloseAll;
  148.       ELSE
  149.         Exit;
  150.       END; { CASE }
  151.       ClearEvent(Event);
  152.     END;
  153. END;
  154.  
  155. PROCEDURE THouseCalcApp.NewMortgage;
  156.  
  157. VAR
  158.   Code       : Integer;
  159.   R          : TRect;
  160.   Control    : Word;
  161.   ThisMortgage     : PMortgageView;
  162.   InitMortgageData : MortgageDialogData;
  163.  
  164. BEGIN
  165.   { First we need a dialog to get the intial mortgage values from }
  166.   { the user.  The dialog appears *before* the mortgage window!   }
  167.   WITH InitMortgageData DO
  168.     BEGIN
  169.       PrincipalData := 100000;
  170.       InterestData  := 10.0;
  171.       PeriodsData   := 360;
  172.     END;
  173.   InitDialog^.SetData(InitMortgageData);
  174.   Control := Desktop^.ExecView(InitDialog);
  175.    IF Control <> cmCancel THEN  { Create a new mortgage object: }
  176.      BEGIN
  177.        R.Assign(5,5,45,20);
  178.        Inc(WindowCount);
  179.        { Get data from the initial mortgage dialog: }
  180.        InitDialog^.GetData(InitMortgageData);
  181.        { Call the constructor for the mortgage window: }
  182.        ThisMortgage :=
  183.          New(PMortgageView,Init(R,'Mortgage',WindowCount,
  184.                                 InitMortgageData));
  185.  
  186.        { Insert the mortgage window into the desktop: }
  187.        Desktop^.Insert(ThisMortgage);
  188.      END;
  189. END;
  190.  
  191. PROCEDURE THouseCalcApp.InitMenuBar;
  192.  
  193. VAR
  194.   R : TRect;
  195.  
  196. BEGIN
  197.   GetExtent(R);
  198.   R.B.Y := R.A.Y + 1;  { Define 1-line menu bar }
  199.  
  200.   MenuBar := New(PMenuBar,Init(R,NewMenu(
  201.     NewSubMenu('~M~ortgage',hcNoContext,NewMenu(
  202.       NewItem('~N~ew','F6',kbF6,cmNewMortgage,hcNoContext,
  203.       NewItem('~C~lose all','F7',kbF7,cmCloseAll,hcNoContext,
  204.       NIL))),
  205.     NIL)
  206.   )));
  207. END;
  208.  
  209. {---------------------------------}
  210. {   METHODS: TMortgageTopInterior }
  211. {---------------------------------}
  212.  
  213. CONSTRUCTOR TMortgageTopInterior.Init(VAR Bounds : TRect);
  214.  
  215. BEGIN
  216.   TView.Init(Bounds);  { Call ancestor's constructor }
  217. END;
  218.  
  219. PROCEDURE TMortgageTopInterior.Draw;
  220.  
  221. VAR
  222.   YRun  : Integer;
  223.   Color : Byte;
  224.   B     : TDrawBuffer;
  225.   STemp : String[20];
  226.  
  227. BEGIN
  228.   Color := GetColor(1);
  229.   MoveChar(B,' ',Color,Size.X);    { Clear the buffer to spaces }
  230.   MoveStr(B,'  Principal    Interest   Periods',Color);
  231.   WriteLine(0,0,Size.X,1,B);
  232.  
  233.   MoveChar(B,' ',Color,Size.X);    { Clear the buffer to spaces }
  234.   { Here we convert payment data to strings for display: }
  235.   Str(Mortgage^.Principal:7:2,STemp);
  236.   MoveStr(B[2],STemp,Color);         { At beginning of buffer B }
  237.   Str(Mortgage^.Interest*100:7:2,STemp);
  238.   MoveStr(B[14],STemp,Color);      { At position 11 of buffer B }
  239.   Str(Mortgage^.Periods:4,STemp);
  240.   MoveStr(B[27],STemp,Color);      { At position 23 of buffer B }
  241.   WriteLine(0,1,Size.X,1,B);
  242.  
  243.   MoveChar(B,' ',Color,Size.X);    { Clear the buffer to spaces }
  244.   WriteLine(0,2,Size.X,1,B);
  245.  
  246.   MoveChar(B,' ',Color,Size.X);    { Clear the buffer to spaces }
  247.   MoveStr(B,'Paymt #  Int.    Prin.    Balance',Color);
  248.   WriteLine(0,3,Size.X,1,B);
  249.  
  250. END;
  251.  
  252. {------------------------------------}
  253. {   METHODS: TMortgageBottomInterior }
  254. {------------------------------------}
  255.  
  256. CONSTRUCTOR TMortgageBottomInterior.Init(VAR Bounds : TRect;
  257.                                          AHScrollBar, AVScrollBar :
  258.                                          PScrollBar);
  259. BEGIN
  260.   TScroller.Init(Bounds,AHScrollBar,AVScrollBar);
  261.   GrowMode := gfGrowHiX + gfGrowHiY;
  262.   Options := Options OR ofFramed;
  263. END;
  264.  
  265. PROCEDURE TMortgageBottomInterior.Draw;
  266.  
  267. VAR
  268.   Color : Byte;
  269.   B     : TDrawBuffer;
  270.   YRun  : Integer;
  271.   STemp : String[20];
  272.  
  273. BEGIN
  274.   Color := GetColor(1);
  275.   FOR YRun := 0 TO Size.Y-1 DO
  276.     BEGIN
  277.       MoveChar(B,' ',Color,Size.X);    { Clear the buffer to spaces }
  278.       Str(Delta.Y+YRun+1:4,STemp);
  279.       MoveStr(B,STemp+':',Color);        { At beginning of buffer B }
  280.       { Here we convert payment data to strings for display: }
  281.       Str(Mortgage^.Payments^[Delta.Y+YRun+1].PayPrincipal:7:2,STemp);
  282.       MoveStr(B[6],STemp,Color);         { At beginning of buffer B }
  283.       Str(Mortgage^.Payments^[Delta.Y+YRun+1].PayInterest:7:2,STemp);
  284.       MoveStr(B[15],STemp,Color);      { At position 11 of buffer B }
  285.       Str(Mortgage^.Payments^[Delta.Y+YRun+1].Balance:10:2,STemp);
  286.       MoveStr(B[24],STemp,Color);      { At position 23 of buffer B }
  287.       WriteLine(0,YRun,Size.X,1,B);
  288.     END;
  289. END;
  290.  
  291. {------------------------------}
  292. {   METHODS: TMortgageView     }
  293. {------------------------------}
  294.  
  295. CONSTRUCTOR TMortgageView.Init(VAR Bounds  : TRect;
  296.                                    ATitle  : TTitleStr;
  297.                                    ANumber : Integer;
  298.                                    InitMortgageData :
  299.                                    MortgageDialogData);
  300. VAR
  301.   TopInterior    : PMortgageTopInterior;
  302.   BottomInterior : PMortgageBottomInterior;
  303.   HScrollBar,VScrollBar : PScrollBar;
  304.   R,S  : TRect;
  305.  
  306. BEGIN
  307.   TWindow.Init(Bounds,ATitle,ANumber); { Call ancestor's constructor }
  308.   { Call the Mortgage object's constructor using dialog data: }
  309.   WITH InitMortgageData DO
  310.     Mortgage.Init(PrincipalData,
  311.                   InterestData / 100,
  312.                   PeriodsData,
  313.                   12);
  314.   { Here we set up a window with *two* interiors, one scrollable, one }
  315.   { static.  It's all in the way that you define the bounds, mostly:  }
  316.   GetClipRect(Bounds);             { Get bounds for interior of view  }
  317.   Bounds.Grow(-1,-1);      { Shrink those bounds by 1 for both X & Y  }
  318.   { Define a rectangle to embrace the upper of the two interiors:     }
  319.   R.Assign(Bounds.A.X,Bounds.A.Y,Bounds.B.X,Bounds.A.Y+4);
  320.   TopInterior := New(PMortgageTopInterior,Init(R));
  321.   TopInterior^.Mortgage := @Mortgage;
  322.   Insert(TopInterior);
  323.  
  324.   { Define a rectangle to embrace the lower of two interiors: }
  325.   R.Assign(Bounds.A.X,Bounds.A.Y+5,Bounds.B.X,Bounds.B.Y);
  326.  
  327.   { Create scroll bars for both mouse & keyboard input: }
  328.   VScrollBar := StandardScrollBar(sbVertical + sbHandleKeyboard);
  329.   { We have to adjust vertical bar to fit bottom interior: }
  330.   VScrollBar^.Origin.Y := R.A.Y;       { Adjust top Y value }
  331.   VScrollBar^.Size.Y := R.B.Y - R.A.Y; { Adjust size }
  332.   { The horizontal scroll bar, on the other hand, is standard: }
  333.   HScrollBar := StandardScrollBar(sbHorizontal + sbHandleKeyboard);
  334.  
  335.   { Create bottom interior object with scroll bars: }
  336.   BottomInterior :=
  337.     New(PMortgageBottomInterior,Init(R,HScrollBar,VScrollBar));
  338.   { Make copy of pointer to mortgage object: }
  339.   BottomInterior^.Mortgage := @Mortgage;
  340.   { Set the limits for the scroll bars: }
  341.   BottomInterior^.SetLimit(80,InitMortgageData.PeriodsData);
  342.   { Insert the interior into the window: }
  343.   Insert(BottomInterior);
  344. END;
  345.  
  346. PROCEDURE TMortgageView.HandleEvent(Var Event : TEvent);
  347.  
  348. BEGIN
  349.   TWindow.HandleEvent(Event);
  350.   IF Event.What = evCommand THEN
  351.     BEGIN
  352.       CASE Event.Command OF
  353.         cmPrintSummary : PrintSummary;
  354.       ELSE
  355.         Exit;
  356.       END; { CASE }
  357.       ClearEvent(Event);
  358.     END
  359.   ELSE
  360.     IF Event.What = evBroadcast THEN
  361.       CASE Event.Command OF
  362.         cmCloseBC : Done
  363.       END; { CASE }
  364. END;
  365.  
  366. PROCEDURE TMortgageView.PrintSummary;
  367.  
  368. BEGIN
  369. END;
  370.  
  371. DESTRUCTOR TMortgageView.Done;
  372.  
  373. BEGIN
  374.   Mortgage.Done;  { Dispose of the mortgage object's memory }
  375.   TWindow.Done;   { Call parent's destructor to dispose of window }
  376. END;
  377.  
  378. { MAIN PROGRAM OBJECT DECLARE & RUN: }
  379.  
  380. VAR
  381.   HouseCalc : THouseCalcApp;
  382.  
  383. BEGIN
  384.   HouseCalc.Init;
  385.   HouseCalc.Run;
  386.   HouseCalc.Done;
  387. END.
  388.  
  389.